from util_libc import *
b = bytes()
# 1、使用C语言编译编译一个函数add 函数计算2个uint64相加，反编译获取机器码，获取等效的代码流。
# 1.1、函数的编写必须使用引用完成，不能直接计算变量。
# 1.2、不能在栈空间分配结构体完成计算，否则返回时原数据不改变
# 2、使用mmap函数 向python进程空间 mmap一个 4096 直接的空间（一张页内存），要求页存在读写执行权限。（可以共享）
# 2.1、如果mmap的页不给执行权限，那么会导致CPU直接except段错误。
# 3、使用create_string_buffer创建的二进制可自行程序，拷贝到mmap的内存里。
# 4、构造入参结构体，当创建线程需要多个入参时，只能使用结构体封装，然后在传入。
# 5、创建新的执行线程或者进程，将启动函数指针和入参结构体送入线程执行流中。
# 6、直接获取结构体里面的返回值当做执行器。
# 【另外】：线程的函数体进出已经包含了栈帧平衡所以返回时直接保持一致

# 打印命令
# objdump --disassemble -M intel add_struct.o
# C 函数函数体
# uint64_t add(uint64_t &a,uint64_t &b)
# {
# return a + b;
# }
#   0:	55                   	push   rbp
#   1:	48 89 e5             	mov    rbp,rsp
#   4:	48 89 7d f8          	mov    QWORD PTR [rbp-0x8],rdi
#   8:	48 89 75 f0          	mov    QWORD PTR [rbp-0x10],rsi
#   c:	48 8b 45 f8          	mov    rax,QWORD PTR [rbp-0x8]
#  10:	48 8b 10             	mov    rdx,QWORD PTR [rax]
#  13:	48 8b 45 f0          	mov    rax,QWORD PTR [rbp-0x10]
#  17:	48 8b 00             	mov    rax,QWORD PTR [rax]
#  1a:	48 01 d0             	add    rax,rdx
#  1d:	5d                   	pop    rbp
#  1e:	c3

# void* add_struct(void *data)  此版结构体入参
# {
# args * input = (args*)data;
# input->c = input->a + input->b;
# return((void*)0);
# }
# 0000000000000000 <_Z10add_structPv>:
#    0:	55                   	push   rbp
#    1:	48 89 e5             	mov    rbp,rsp
#    4:	48 89 7d e8          	mov    QWORD PTR [rbp-0x18],rdi
#    8:	48 8b 45 e8          	mov    rax,QWORD PTR [rbp-0x18]
#    c:	48 89 45 f8          	mov    QWORD PTR [rbp-0x8],rax
#   10:	48 8b 45 f8          	mov    rax,QWORD PTR [rbp-0x8]
#   14:	48 8b 10             	mov    rdx,QWORD PTR [rax]
#   17:	48 8b 45 f8          	mov    rax,QWORD PTR [rbp-0x8]
#   1b:	48 8b 40 08          	mov    rax,QWORD PTR [rax+0x8]
#   1f:	48 01 c2             	add    rdx,rax
#   22:	48 8b 45 f8          	mov    rax,QWORD PTR [rbp-0x8]
#   26:	48 89 50 10          	mov    QWORD PTR [rax+0x10],rdx
#   2a:	b8 00 00 00 00       	mov    eax,0x0
#   2f:	5d                   	pop    rbp
#   30:	c3                   	ret
# objdump --section=.text -s add_struct.o
# Contents of section .text:
#  0000 554889e5 48897de8 488b45e8 488945f8  UH..H.}.H.E.H.E.
#  0010 488b45f8 488b1048 8b45f848 8b400848  H.E.H..H.E.H.@.H
#  0020 01c2488b 45f84889 5010b800 0000005d  ..H.E.H.P......]
#  0030 c3

addr = lib_c_mmap(4096)
print(r'mmap 获得的物理内存 可以执行的页 ',addr, hex(addr))

# time.sleep(9999999)
tid = c_ulong(0)

# 组装线程结构体
class ARGS(Structure):
    # 变量名字符串、变量类型、变量长度
    _fields_ = [('a', c_ulonglong), ('b', c_ulonglong), ('c', c_ulonglong)]

args = ARGS()
args.a, args.b, args.c = 44, 55, 0
print(r'len(args) = ', sizeof(args))
# 使用create_string_buffer 创建的内存空间无法执行代码
# add = create_string_buffer(b'\x55\x48\x89\xe5\x48\x89\x7d\xf8\x48\x89\x75\xf0\x48\x8b\x45\xf8\x48\x8b\x10\x48\x8b\x45\xf0\x48\x8b\x00\x48\x01\xd0\x5d\xc3')
# add_struct = create_string_buffer(b'\x55\x48\x89\xe5\x48\x89\x7d\xe8\x48\x8b\x45\xe8\x48\x89\x45\xf8\x48\x8b\x45\xf8\x48\x8b\x10\x48\x8b\x45\xf8\x48\x8b\x40\x08\x48\x01\xc2\x48\x8b\x45\xf8\x48\x89\x50\x10\xb8\x00\x00\x00\x00\x5d\xc3')
code_add_struct = b'\x55\x48\x89\xe5\x48\x89\x7d\xe8\x48\x8b\x45\xe8\x48\x89\x45\xf8\x48\x8b\x45\xf8\x48\x8b\x10\x48\x8b\x45\xf8\x48\x8b\x40\x08\x48\x01\xc2\x48\x8b\x45\xf8\x48\x89\x50\x10\xb8\x00\x00\x00\x00\x5d\xc3'
add_struct = create_string_buffer(code_add_struct)
print(r'fun add_struct = ', byref(add_struct), r' len = ', len(code_add_struct))
# print(r'addr of input =', byref(args.a), byref(args.b), byref(args.c))

cp_ret = lib_c_memcpy(c_void_p(addr), byref(add_struct), c_int(len(code_add_struct)))

print(r'拷贝内存到 mmap内存中 = ', cp_ret)
print(r'创建线程 计算 44 + 55 ', lib_pthread_create(byref(tid), None, c_void_p(addr), byref(args)))
print(r'线程 tid = ', tid)
print(r'线程 join', lib_pthread_join(tid))
print(r'计算结果 = ', args.c)

# 最后检查调用的函数体在内存中的位置，debug python进程
# gdb 启动以后找到buff所在地址 dump add_struct 函数体
# (gdb) disas /r 0x00007ffff7e57e70,0x00007ffff7e57ea1
# Dump of assembler code from 0x7ffff7e57e70 to 0x7ffff7e57ea1:
# => 0x00007ffff7e57e70:	55	push   %rbp
#    0x00007ffff7e57e71:	48 89 e5	mov    %rsp,%rbp
#    0x00007ffff7e57e74:	48 89 7d e8	mov    %rdi,-0x18(%rbp)
#    0x00007ffff7e57e78:	48 8b 45 e8	mov    -0x18(%rbp),%rax
#    0x00007ffff7e57e7c:	48 89 45 f8	mov    %rax,-0x8(%rbp)
#    0x00007ffff7e57e80:	48 8b 45 f8	mov    -0x8(%rbp),%rax
#    0x00007ffff7e57e84:	48 8b 10	mov    (%rax),%rdx
#    0x00007ffff7e57e87:	48 8b 45 f8	mov    -0x8(%rbp),%rax
#    0x00007ffff7e57e8b:	48 8b 40 08	mov    0x8(%rax),%rax
#    0x00007ffff7e57e8f:	48 01 c2	add    %rax,%rdx
#    0x00007ffff7e57e92:	48 8b 45 f8	mov    -0x8(%rbp),%rax
#    0x00007ffff7e57e96:	48 89 50 10	mov    %rdx,0x10(%rax)
#    0x00007ffff7e57e9a:	b8 00 00 00 00	mov    $0x0,%eax
#    0x00007ffff7e57e9f:	5d	pop    %rbp
#    0x00007ffff7e57ea0:	c3	retq
# End of assembler dump.
#
# Thread 2 "main" hit Breakpoint 2, add_struct (data=0x7fffffffe4b0) at add_struct.c:11
# (gdb) x /24fb 0x7fffffffe4b0  (检验穿进去的结构体 刚好是3个uint64 24直接小端存储)
# 0x7fffffffe4b0:	44	0	0	0	0	0	0	0
# 0x7fffffffe4b8:	55	0	0	0	0	0	0	0
# 0x7fffffffe4c0:	0	0	0	0	0	0	0	0
